// ==========================================================================
// GFast自动生成logic操作代码。
// 生成日期：2024-04-24 15:48:40
// 生成路径: internal/app/business/logic/performances.go
// 生成人：周志雄
// desc:演出节目
// company:云南奇讯科技有限公司
// ==========================================================================

package logic

import (
	"context"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/util/gconv"
	"github.com/tiger1103/gfast/v3/api/v1/business"
	"github.com/tiger1103/gfast/v3/internal/app/business/dao"
	"github.com/tiger1103/gfast/v3/internal/app/business/model"
	"github.com/tiger1103/gfast/v3/internal/app/business/model/do"
	"github.com/tiger1103/gfast/v3/internal/app/business/service"
	"github.com/tiger1103/gfast/v3/internal/app/system/consts"
	"github.com/tiger1103/gfast/v3/library/liberr"
)

func init() {
	service.RegisterPerformances(New())
}

func New() *sPerformances {
	return &sPerformances{}
}

type sPerformances struct{}

func (s *sPerformances) List(ctx context.Context, req *business.PerformancesSearchReq) (listRes *business.PerformancesSearchRes, err error) {
	listRes = new(business.PerformancesSearchRes)
	err = g.Try(ctx, func(ctx context.Context) {
		m := dao.Performances.Ctx(ctx).WithAll()
		if req.PerformanceName != "" {
			m = m.Where(dao.Performances.Columns().PerformanceName+" like ?", "%"+req.PerformanceName+"%")
		}
		if req.PerformanceDate != "" {
			m = m.Where(dao.Performances.Columns().PerformanceDate+" = ?", gconv.Time(req.PerformanceDate))
		}
		if req.PerformanceTime != "" {
			m = m.Where(dao.Performances.Columns().PerformanceTime+" = ?", req.PerformanceTime)
		}
		if req.StartSaleTime != "" {
			m = m.Where(dao.Performances.Columns().StartSaleTime+" = ?", gconv.Time(req.StartSaleTime))
		}
		if req.TicketReclaimTime != "" {
			m = m.Where(dao.Performances.Columns().TicketReclaimTime+" = ?", gconv.Time(req.TicketReclaimTime))
		}
		if req.TicketPickupTime != "" {
			m = m.Where(dao.Performances.Columns().TicketPickupTime+" = ?", gconv.Time(req.TicketPickupTime))
		}
		if req.VenueId != "" {
			m = m.Where(dao.Performances.Columns().VenueId+" = ?", gconv.Int(req.VenueId))
		}
		if req.ProgramTypeId != "" {
			m = m.Where(dao.Performances.Columns().ProgramTypeId+" = ?", gconv.Int(req.ProgramTypeId))
		}
		if req.PageNum == 0 {
			req.PageNum = 1
		}
		listRes.CurrentPage = req.PageNum
		if req.PageSize == 0 {
			req.PageSize = consts.PageSize
		}
		order := "id asc"

		// TODO 先查询基础数据
		var res []*model.PerformancesInfoResVo
		err = m.Fields("performances.*, venues.venue_name AS venueName, program_types.type_name AS programTypeName ").
			InnerJoin("venues on venues.id = performances.venue_id").
			InnerJoin("program_types on program_types.id = performances.program_type_id").Page(req.PageNum, req.PageSize).Order(order).Scan(&res)
		liberr.ErrIsNil(ctx, err, "获取数据失败")
		listRes.List = make([]*model.PerformancesListResVo, len(res))

		// TODO 遍历演出节目数据、根据演出节目的ID获取票的统计信息
		for k, v := range res {
			var seatsList []model.SeatsStatusStatic
			seatsList, err = service.Seats().GetSeatsStaticInfo(ctx, v.Id)
			liberr.ErrIsNil(ctx, err, "获取演出节目实时票信息失败")

			// TODO 查询对应场次的基本数据
			listRes.List[k] = &model.PerformancesListResVo{
				Id:                v.Id,
				PerformanceName:   v.PerformanceName,
				PerformanceDate:   v.PerformanceDate,
				PerformanceTime:   v.PerformanceTime,
				StartSaleTime:     v.StartSaleTime,
				TicketReclaimTime: v.TicketReclaimTime,
				TicketPickupTime:  v.TicketPickupTime,
				VenueId:           v.VenueId,
				VenueName:         v.VenueName,
				ProgramTypeId:     v.ProgramTypeId,
				ProgramTypeName:   v.ProgramTypeName,
				CreatedAt:         v.CreatedAt,
				SeatsStatusList:   seatsList,
			}
		}
		listRes.Total = len(listRes.List)
		liberr.ErrIsNil(ctx, err, "获取总行数失败")
	})
	return
}

func (s *sPerformances) GetById(ctx context.Context, id int) (res *model.PerformancesInfoRes, err error) {
	err = g.Try(ctx, func(ctx context.Context) {
		err = dao.Performances.Ctx(ctx).WithAll().Where(dao.Performances.Columns().Id, id).Scan(&res)
		liberr.ErrIsNil(ctx, err, "获取信息失败")
	})
	return
}

func (s *sPerformances) Add(ctx context.Context, req *business.PerformancesAddReq) (err error) {
	err = g.Try(ctx, func(ctx context.Context) {
		// 插入演出节目的基本信息并获取新增记录的ID
		performanceId, err := dao.Performances.Ctx(ctx).InsertAndGetId(do.Performances{
			PerformanceName:   req.PerformanceName,
			PerformanceDate:   req.PerformanceDate,
			PerformanceTime:   req.PerformanceTime,
			StartSaleTime:     req.StartSaleTime,
			TicketReclaimTime: req.TicketReclaimTime,
			TicketPickupTime:  req.TicketPickupTime,
			VenueId:           req.VenueId,
			ProgramTypeId:     req.ProgramTypeId,
		})
		liberr.ErrIsNil(ctx, err, "添加演出失败")

		// TODO 查询指定场馆的座位信息
		param := business.GetSeatsByVenueIdReq{
			VenueId: req.VenueId,
		}
		res, err := service.Venues().GetSeatsById(ctx, &param)
		if err != nil {
			return
		}

		// TODO 处理预定座位的ID列表
		reservedIdsMap := make(map[int]bool)
		for _, id := range req.ReservedIds {
			reservedIdsMap[id] = true
		}

		// 准备插入节目座位预定表的数据
		var booksEntries []do.Books
		ticketTypeCounts := make(map[int]int) // 座位类型统计
		for _, seat := range res.Seats {
			status := 2 // 默认为未选
			if reservedIdsMap[seat.Id] {
				status = 3 // 设置为已预留
			}
			booksEntries = append(booksEntries, do.Books{
				ShowingId: performanceId,
				SeatId:    seat.Id,
				Status:    status,
			})
			ticketTypeCounts[seat.TicketType]++ // 统计不同类型座位的数量
			if status == 3 {
				ticketTypeCounts[seat.TicketType]-- // 减去被预留的座位数量
			}
		}

		// 批量插入座位预订信息到节目座位预定表的数据
		_, err = dao.Books.Ctx(ctx).Data(booksEntries).Insert()
		liberr.ErrIsNil(ctx, err, "批量插入座位预订信息失败")

		// TODO 插入座位售卖信息到节目票剩余表
		var ticketRemainEntries []do.TicketRemain
		for ticketType, count := range ticketTypeCounts {
			ticketRemainEntries = append(ticketRemainEntries, do.TicketRemain{
				PerformanceId: performanceId,
				TicketType:    ticketType,
				RemainNum:     count,
			})
		}
		_, err = dao.TicketRemain.Ctx(ctx).Data(ticketRemainEntries).Insert()
		liberr.ErrIsNil(ctx, err, "新增演出节目失败")
	})
	return
}

func (s *sPerformances) Edit(ctx context.Context, req *business.PerformancesEditReq) (err error) {
	err = g.Try(ctx, func(ctx context.Context) {
		_, err = dao.Performances.Ctx(ctx).WherePri(req.Id).Update(do.Performances{
			PerformanceName:   req.PerformanceName,
			PerformanceDate:   req.PerformanceDate,
			PerformanceTime:   req.PerformanceTime,
			StartSaleTime:     req.StartSaleTime,
			TicketReclaimTime: req.TicketReclaimTime,
			TicketPickupTime:  req.TicketPickupTime,
			VenueId:           req.VenueId,
			ProgramTypeId:     req.ProgramTypeId,
		})
		liberr.ErrIsNil(ctx, err, "修改失败")
	})
	return
}

func (s *sPerformances) Delete(ctx context.Context, ids []int) (err error) {
	err = g.Try(ctx, func(ctx context.Context) {
		_, err = dao.Performances.Ctx(ctx).Delete(dao.Performances.Columns().Id+" in (?)", ids)
		liberr.ErrIsNil(ctx, err, "删除失败")
	})
	return
}
